home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / DiskUtil / CD-ROM / AmiCDROM-1.15.lha / AmiCDROM / src / iso9660.c < prev    next >
C/C++ Source or Header  |  1994-11-03  |  22KB  |  871 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 20-Aug-94   fmu   Uses function Find_Last_Session() before the traversal
  14.  *                   of the TOC.
  15.  * 17-Jul-94   fmu   Tries to cope with CDROMs which have an incorrect TOC.
  16.  * 17-May-94   fmu   New option MAYBELOWERCASE (=ML).
  17.  * 25-Apr-94   fmu   The extented attribute record length has to be
  18.  *                   considered when reading file sections.
  19.  * 17-Feb-94   fmu   Volume ID must not be longer than 30 characters.
  20.  * 05-Feb-94   fmu   Added support for relocated directories.
  21.  * 07-Jan-94   fmu   Support for drives which don't support the SCSI-2
  22.  *                   READ TOC command.
  23.  * 01-Jan-94   fmu   Added multisession support.
  24.  * 11-Dec-93   fmu   Fixed bug in Iso_Find_Parent().
  25.  * 02-Dec-93   fmu   Bugfix: a logical block of a file extent must not
  26.  *                   necessarily start at a logical sector border.
  27.  * 29-Nov-93   fmu   - New function Iso_Block_Size().
  28.  *                   - Support for variable logical block sizes.
  29.  * 15-Nov-93   fmu   Uses_High_Sierra_Protocol added.
  30.  * 13-Nov-93   fmu   Bad iso_errno return value in Iso_Open_Obj_In_Directory
  31.  *                   corrected.
  32.  * 12-Oct-93   fmu   Adapted to new VOLUME and CDROM_OBJ structures.
  33.  * 24-Sep-93   fmu   Two further bugs in Seek_Position fixed.
  34.  * 16-Sep-93   fmu   Fixed bug in Seek_Position.
  35.  * 16-Sep-93   fmu   Bugfix: Top level object recognition in CDROM_Info
  36.  *                   had to be changed for Rock Ridge disks.
  37.  */
  38.  
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <ctype.h>
  42.  
  43. #include <exec/types.h>
  44. #include <exec/memory.h>
  45.  
  46. #include <clib/exec_protos.h>
  47. #include <clib/utility_protos.h>
  48.  
  49. #ifdef LATTICE
  50. #include <pragmas/exec_pragmas.h>
  51. #include <pragmas/utility_pragmas.h>
  52. #endif
  53.  
  54. #include "cdrom.h"
  55. #include "iso9660.h"
  56. #include "rock.h"
  57.  
  58. extern struct Library *UtilityBase;
  59.  
  60. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *);
  61.  
  62. int iso_errno;
  63.  
  64. #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
  65. #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
  66.  
  67. /* Check whether the given volume uses the ISO 9660 Protocol.
  68.  * The protocol is identified by the sequence
  69.  *            'C' 'D' '0' '0' '1'
  70.  * in the 2nd..6th byte of sector 16 of a track.
  71.  *
  72.  * All data tracks on the disk are examined.
  73.  *
  74.  * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
  75.  */
  76.  
  77. t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
  78. {
  79.   int i, len;
  80.   t_ulong *buf;
  81.  
  82.   /* If Data_Tracks() returns -1, then the drive probably doesn't support
  83.    * the SCSI-2 READ TOC command.
  84.    */
  85.   if (p_cdrom->use_trackdisk ||
  86.       (len = Data_Tracks (p_cdrom, &buf)) < 0) {
  87.     *p_offset = 0;
  88.     if (!Read_Sector (p_cdrom, 16))
  89.       return FALSE;  
  90.     return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
  91.   }
  92.  
  93.   if (len == 0)
  94.     return FALSE;
  95.  
  96.   /* Use a vendor-specific command to find the offset of the last
  97.    * session:
  98.    */
  99.   if (Find_Last_Session (p_cdrom, p_offset) &&
  100.       Read_Sector (p_cdrom, 16 + *p_offset) &&
  101.       strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  102.     FreeVec (buf);
  103.     return TRUE;
  104.   }
  105.  
  106.   /* Search all data tracks for valid primary volume descriptors: */
  107.   for (i=len-1; i>=0; i--) {
  108.     *p_offset = buf[i];
  109.     if (!Read_Sector (p_cdrom, 16 + *p_offset))
  110.       continue;
  111.     if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  112.       FreeVec (buf);
  113.       return TRUE;
  114.     }
  115.   }
  116.  
  117.   FreeVec (buf);
  118.  
  119.   /* On some disks, the information in the TOC may not be valid. Therefore
  120.    * also check sector 16:
  121.    */
  122.   if (!Read_Sector (p_cdrom, 16))
  123.     return FALSE;
  124.   if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  125.     *p_offset = 0;
  126.     return TRUE;
  127.   }
  128.  
  129.   return FALSE;
  130. }
  131.  
  132. /* Check whether the given volume uses the High Sierra Protocol.
  133.  * The protocol is identified by the sequence
  134.  *            'C' 'D' 'R' 'O' 'M'
  135.  * in the 10th..14th byte of sector 16.
  136.  *
  137.  * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
  138.  */
  139.  
  140. t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
  141. {
  142.   if (!Read_Sector (p_cdrom, 16))
  143.     return FALSE;
  144.   
  145.   return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
  146. }
  147.  
  148. t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset)
  149. {
  150.   long loc = 16 + p_offset;
  151.   extern t_handler g_iso_handler, g_rr_handler;
  152.  
  153.   if (p_volume->protocol == PRO_ISO)
  154.     p_volume->handler = &g_iso_handler;
  155.   else
  156.     p_volume->handler = &g_rr_handler;
  157.  
  158.   p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC);
  159.   if (!p_volume->vol_info) {
  160.     iso_errno = ISOERR_NO_MEMORY;
  161.     return FALSE;
  162.   }
  163.  
  164.   for (;;) {
  165.     if (!Read_Sector (p_volume->cd, loc)) {
  166.       iso_errno = ISOERR_SCSI_ERROR;
  167.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  168.       return FALSE;
  169.     }
  170.  
  171.     if (p_volume->cd->buffer[0] == 1) {
  172.       memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
  173.       break;
  174.     }
  175.     
  176.     if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
  177.       iso_errno = ISOERR_NO_PVD;
  178.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  179.       return FALSE;
  180.     }
  181.     
  182.     loc++;
  183.   }
  184.   
  185.   VOL(p_volume,skip) = p_skip;
  186.  
  187.   switch (VOL(p_volume,pvd).block_size_m) {
  188.   case 512:
  189.     VOL(p_volume,blockshift) = 2;
  190.     break;
  191.   case 1024:
  192.     VOL(p_volume,blockshift) = 1;
  193.     break;
  194.   case 2048:
  195.   default:
  196.     VOL(p_volume,blockshift) = 0;
  197.     break;
  198.   }
  199.  
  200.   /* Look at the system ID to find out if the CD is supposed
  201.    * to feature proper file names. These are CDs made for use
  202.    * with the CDTV and the CD³² (both share the "CDTV" system ID)
  203.    * and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
  204.    * created by Mkisofs. If any of these IDs is found the
  205.    * file name to lower case conversion is temporarily
  206.    * disabled if the "ML=MAYBELOWERCASE" option has been selected.
  207.    */
  208.  
  209.   if (p_volume->protocol == PRO_ROCK ||
  210.       !strncmp(VOL(p_volume,pvd).system_id,"CDTV",4) ||
  211.       !strncmp(VOL(p_volume,pvd).system_id,"AMIGA",5))
  212.     p_volume->mixed_char_filenames = TRUE;
  213.   else
  214.     p_volume->mixed_char_filenames = FALSE;
  215.  
  216.   return TRUE;
  217. }
  218.  
  219. void Iso_Close_Vol_Info (VOLUME *p_volume)
  220. {
  221.   FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  222. }
  223.  
  224. CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
  225. {
  226.   CDROM_OBJ *obj;
  227.  
  228.   obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
  229.   if (!obj) {
  230.     iso_errno = ISOERR_NO_MEMORY;
  231.     return NULL;
  232.   }
  233.  
  234.   obj->obj_info = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  235.   if (!obj->obj_info) {
  236.     FreeMem (obj, sizeof (CDROM_OBJ));
  237.     return NULL;
  238.   }
  239.  
  240.   OBJ(obj,dir) = AllocMem (p_length_of_dir_record, MEMF_PUBLIC);
  241.   if (!OBJ(obj,dir)) {
  242.     iso_errno = ISOERR_NO_MEMORY;
  243.     FreeMem (obj->obj_info, sizeof (t_iso_obj_info));
  244.     FreeMem (obj, sizeof (CDROM_OBJ));
  245.     return NULL;
  246.   }
  247.  
  248.   return obj;
  249. }
  250.  
  251. /* Get the "CDROM object" for the root directory of the volume.
  252.  */
  253.  
  254. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
  255. {
  256.   CDROM_OBJ *obj;
  257.  
  258.   obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
  259.   if (!obj)
  260.     return NULL;
  261.  
  262.   obj->directory_f = TRUE;
  263.   obj->volume = p_volume;
  264.   obj->pos = 0;
  265.   memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
  266.  
  267.   return obj;
  268. }
  269.  
  270. /* Test on equality of directory names (ignoring case).
  271.  */
  272.  
  273. int Directory_Names_Equal (char *p_iso_name, int p_length, char *p_name)
  274. {
  275.   return Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  276.        p_name[p_length] == 0;
  277. }
  278.  
  279. /* Compare the name of the directory entry p_iso_name (with length p_length)
  280.  * with the C string p_name, and return 1 iff both strings are equal.
  281.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  282.  *       name (without version number).
  283.  */
  284.  
  285. int Names_Equal (char *p_iso_name, int p_length, char *p_name)
  286. {
  287.   int pos;
  288.  
  289.   if (Strncasecmp (p_iso_name, p_name, p_length) == 0 &&
  290.       p_name[p_length] == 0)
  291.     return TRUE;
  292.   
  293.   /* compare without version number: */
  294.   
  295.   for (pos=p_length-1; pos>=0; pos--)
  296.     if (p_iso_name[pos] == ';')
  297.       break;
  298.  
  299.   if (pos>=0)
  300.     return (Strncasecmp (p_iso_name, p_name, pos) == 0 &&
  301.             p_name[pos] == 0);
  302.   else
  303.     return FALSE;
  304. }
  305.  
  306. /* Get a record from a directory.
  307.  * p_location is a LOGICAL BLOCK number.
  308.  */
  309.  
  310. directory_record *Get_Directory_Record (VOLUME *p_volume,
  311.                     unsigned long p_location,
  312.                     unsigned long p_offset)
  313. {
  314.   static unsigned char result[256];
  315.   int len;
  316.   int loc;
  317.   
  318.   loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
  319.   if (!Read_Sector (p_volume->cd, loc)) {
  320.     iso_errno = ISOERR_SCSI_ERROR;
  321.     return NULL;
  322.   }
  323.  
  324.   len = p_volume->cd->buffer[p_offset & 2047];
  325.   if (len)
  326.     memcpy (result, p_volume->cd->buffer + (p_offset & 2047), len);
  327.   else
  328.     result[0] = 0;  /* mark as last record */
  329.   
  330.   return (directory_record *) result;
  331. }
  332.  
  333. /* Create a "CDROM object" for the directory which is located
  334.  * at sector p_location.
  335.  */
  336.  
  337. CDROM_OBJ *Iso_Create_Directory_Obj (VOLUME *p_volume, unsigned long p_location)
  338. {
  339.   directory_record *dir;
  340.   unsigned long loc;
  341.   int offset = 0;
  342.   CDROM_OBJ *obj;
  343.   unsigned long len;
  344.  
  345.   if (p_location == VOL(p_volume,pvd).root.extent_loc_m)
  346.     return Iso_Open_Top_Level_Directory (p_volume);
  347.  
  348.   dir = Get_Directory_Record (p_volume, p_location, 0);
  349.   if (!dir)
  350.     return NULL;
  351.   
  352.   dir = Get_Directory_Record (p_volume, p_location, dir->length);
  353.   if (!dir)
  354.     return NULL;
  355.   
  356.   loc = dir->extent_loc_m;
  357.   len = dir->data_length_m;
  358.   for (;;) {
  359.     if (offset >= len)
  360.       return NULL;
  361.     dir = Get_Directory_Record (p_volume, loc, offset);
  362.     if (!dir)
  363.       return NULL;
  364.     if (!dir->length) {
  365.       /* go to next logical sector: */
  366.       offset = (offset & 0xfffff800) + 2048;
  367.       continue;
  368.     }
  369.     if (dir->extent_loc_m == p_location)
  370.       break;
  371.     offset += dir->length;
  372.   }
  373.  
  374.   obj = Iso_Alloc_Obj (dir->length);
  375.   if (!obj)
  376.     return NULL;
  377.  
  378.   obj->directory_f = TRUE;
  379.   obj->volume = p_volume;
  380.   obj->pos = 0;
  381.   memcpy (OBJ(obj,dir), dir, dir->length);
  382.  
  383.   return obj;
  384. }
  385.  
  386.  
  387. /* Open the object with name p_name in the directory p_dir.
  388.  * p_name must not contain '/' or ':' characters.
  389.  */
  390.  
  391. CDROM_OBJ *Iso_Open_Obj_In_Directory (CDROM_OBJ *p_dir, char *p_name)
  392. {
  393.   unsigned long loc = OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length;
  394.   unsigned long len = OBJ(p_dir,dir)->data_length_m;
  395.   directory_record *dir;
  396.   int offset;
  397.   CDROM_OBJ *obj;
  398.   long cl;
  399.  
  400.   /* skip first two entries: */
  401.  
  402.   dir = Get_Directory_Record (p_dir->volume, loc, 0);
  403.   if (!dir)
  404.     return NULL;
  405.   
  406.   offset = dir->length;
  407.   dir = Get_Directory_Record (p_dir->volume, loc, offset);
  408.   if (!dir)
  409.     return NULL;
  410.  
  411.   offset += dir->length;
  412.   for (;;) {
  413.     if (offset >= len) {
  414.       iso_errno = ISOERR_NOT_FOUND;
  415.       return NULL;
  416.     }
  417.     dir = Get_Directory_Record (p_dir->volume, loc, offset);
  418.     if (!dir)
  419.       return NULL;
  420.     if (!dir->length) {
  421.       /* go to next logical sector: */
  422.       offset = (offset & 0xfffff800) + 2048;
  423.       continue;
  424.     }
  425.     if (p_dir->volume->protocol == PRO_ROCK) {
  426.       char buf[256];
  427.       int len;
  428.  
  429.       if ((len = Get_RR_File_Name (p_dir->volume, dir, buf, sizeof (buf))) > 0 &&
  430.           Strncasecmp (buf, p_name, len) == 0 &&
  431.       p_name[len] == 0)
  432.     break;
  433.     }
  434.  
  435.     if (Names_Equal (dir->file_id, dir->file_id_length, p_name))
  436.       break;
  437.     offset += dir->length;
  438.   }
  439.  
  440.   if (p_dir->volume->protocol == PRO_ROCK &&
  441.       (cl = RR_Child_Link (p_dir->volume, dir)) >= 0)
  442.     return Iso_Create_Directory_Obj (p_dir->volume, cl);
  443.  
  444.   obj = Iso_Alloc_Obj (dir->length);
  445.   if (!obj)
  446.     return NULL;
  447.  
  448.   obj->directory_f = (dir->flags & 2);
  449.   if (p_dir->volume->protocol == PRO_ROCK &&
  450.       Is_A_Symbolic_Link (p_dir->volume, dir)) {
  451.     obj->symlink_f = 1;
  452.     obj->directory_f = 0;
  453.   }
  454.   memcpy (OBJ(obj,dir), dir, dir->length);
  455.   obj->volume = p_dir->volume;
  456.   obj->pos = 0;
  457.   if (!obj->directory_f)
  458.     OBJ(obj,parent_loc) = loc;
  459.  
  460.   return obj;
  461. }
  462.  
  463. /* Close a "CDROM object" and deallocate all associated resources.
  464.  */
  465.  
  466. void Iso_Close_Obj (CDROM_OBJ *p_object)
  467. {
  468.   FreeMem (OBJ(p_object,dir), OBJ(p_object,dir)->length);
  469.   FreeMem (p_object->obj_info, sizeof (t_iso_obj_info));
  470.   FreeMem (p_object, sizeof (CDROM_OBJ));
  471. }
  472.  
  473. /* Read bytes from a file.
  474.  */
  475.  
  476. int Iso_Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  477. {
  478.   unsigned long loc;
  479.   int remain_block, remain_file, remain;
  480.   int len;
  481.   VOLUME *vol = p_file->volume;
  482.   CDROM *cd = vol->cd;
  483.   int buf_pos = 0;
  484.   int todo;
  485.   unsigned long last_loc, ext_loc;
  486.   short blockshift;
  487.   int offset;
  488.   unsigned long firstblock;
  489.  
  490.   if (p_file->pos == OBJ(p_file,dir)->data_length_m)
  491.     /* at end of file: */
  492.     return 0;
  493.  
  494.   blockshift = VOL(vol,blockshift);
  495.   /* 'firstblock' is the first logical block of the file section: */
  496.   firstblock = OBJ(p_file,dir)->extent_loc_m + OBJ(p_file,dir)->ext_attr_length;
  497.   /*
  498.    * 'offset' is the offset of the first logical block of the file
  499.    * extent from the first logical (2048-byte-)sector.
  500.    */
  501.   if (blockshift)
  502.     offset = ((firstblock & ((1<<blockshift)-1))
  503.               << (11-blockshift));
  504.   else
  505.     offset = 0;
  506.   /*
  507.    * 'ext_loc' is the first logical sector of the file extent.
  508.    * 'loc' is the first logical sector to be read.
  509.    * 'last_loc' is the last logical sector of the file extent.
  510.    */
  511.   ext_loc = firstblock >> blockshift;
  512.   loc = ext_loc + ((p_file->pos + offset) >> 11);
  513.   last_loc = ext_loc + ((OBJ(p_file,dir)->data_length_m + offset - 1) >> 11);
  514.   todo = p_buffer_length;
  515.  
  516.   offset += p_file->pos;
  517.   offset &= 2047;
  518.   remain_block = 2048 - offset;
  519.  
  520.   while (todo) {
  521.     if (!Read_Contiguous_Sectors (cd, loc, last_loc)) {
  522.       iso_errno = ISOERR_SCSI_ERROR;
  523.       return -1;
  524.     }
  525.  
  526.     remain_file = OBJ(p_file,dir)->data_length_m - p_file->pos;
  527.     /* 
  528.      * 'todo' is the number of bytes in p_buffer which haven't been filled yet.
  529.      * 'remain' is remaining number of bytes in cd->buffer.
  530.      */
  531.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  532.     len = (todo < remain) ? todo : remain;
  533.     CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
  534.     buf_pos += len;
  535.     p_file->pos += len;
  536.     todo -= len;
  537.  
  538.     if (p_file->pos >= OBJ(p_file,dir)->data_length_m)
  539.       break;
  540.  
  541.     remain_block = 2048;
  542.     offset = 0;
  543.  
  544.     loc++;
  545.   }
  546.  
  547.   return buf_pos;
  548. }
  549.  
  550. t_ulong Extract_Date (directory_record *p_dir_record)
  551. {
  552.   struct ClockData ClockData;
  553.  
  554.   ClockData.sec   = p_dir_record->second;
  555.   ClockData.min      = p_dir_record->minute;
  556.   ClockData.hour  = p_dir_record->hour;
  557.   ClockData.mday  = p_dir_record->day;
  558.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  559.   ClockData.month = p_dir_record->month;
  560.   ClockData.year  = p_dir_record->year + 1900;
  561.  
  562.   if (CheckDate (&ClockData))
  563.     return Date2Amiga (&ClockData);
  564.   else
  565.     return 0;
  566. }
  567.  
  568. /* Return information on a "CDROM object."
  569.  */
  570.  
  571. int Iso_CDROM_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  572. {
  573.   int len;
  574.  
  575.   if (Iso_Is_Top_Level_Object (p_obj)) {
  576.     p_info->name_length = 1;
  577.     p_info->name[0] = ':';
  578.     p_info->directory_f = TRUE;
  579.     p_info->file_length = 0;
  580.     p_info->date = Volume_Creation_Date (p_obj->volume);
  581.   } else {
  582.     if (p_obj->volume->protocol == PRO_ROCK &&
  583.         (len = Get_RR_File_Name (p_obj->volume, OBJ(p_obj,dir),
  584.                        p_info->name, sizeof (p_info->name))) > 0) {
  585.       p_info->name_length = len;
  586.     } else {
  587.       p_info->name_length = OBJ(p_obj,dir)->file_id_length;
  588.       memcpy (p_info->name, OBJ(p_obj,dir)->file_id, p_info->name_length);
  589.     }
  590.     p_info->directory_f = p_obj->directory_f;
  591.     p_info->symlink_f = p_obj->symlink_f;
  592.     p_info->file_length = OBJ(p_obj,dir)->data_length_m;
  593.     p_info->date = Extract_Date (OBJ(p_obj,dir));
  594.   }
  595.  
  596.   return 1;
  597. }
  598.  
  599. /* Browse all entries in a directory.
  600.  */
  601.  
  602. int Iso_Examine_Next (CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  603.               unsigned long *p_offset)
  604. {
  605.   unsigned long offset;
  606.   directory_record *rec;
  607.   int len;
  608.  
  609.   if (!p_dir->directory_f || p_dir->symlink_f) {
  610.     iso_errno = ISOERR_BAD_ARGUMENTS;
  611.     return 0;
  612.   }
  613.  
  614.   if (*p_offset == 0) {
  615.     /* skip first two directory entries: */
  616.   
  617.     rec = Get_Directory_Record
  618.       (p_dir->volume,
  619.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  620.        0);
  621.     if (!rec)
  622.       return 0;
  623.   
  624.     offset = rec->length;
  625.   
  626.     rec = Get_Directory_Record
  627.       (p_dir->volume,
  628.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  629.        offset);
  630.     if (!rec)
  631.       return 0;
  632.   
  633.     *p_offset = offset + rec->length;
  634.   }
  635.  
  636.   for (;;) {
  637.     if (OBJ(p_dir,dir)->data_length_m <= *p_offset)
  638.       return 0;
  639.  
  640.     rec = Get_Directory_Record
  641.         (p_dir->volume,
  642.        OBJ(p_dir,dir)->extent_loc_m + OBJ(p_dir,dir)->ext_attr_length,
  643.      *p_offset);
  644.     if (!rec)
  645.       return 0;
  646.   
  647.     if (rec->length == 0)
  648.       /* go to next logical sector: */
  649.       *p_offset = (*p_offset & 0xfffff800) + 2048;
  650.     else
  651.       break;
  652.   }
  653.  
  654.   *p_offset += rec->length;
  655.  
  656.   if (p_dir->volume->protocol == PRO_ROCK &&
  657.       (len = Get_RR_File_Name (p_dir->volume, rec,
  658.                          p_info->name, sizeof (p_info->name))) > 0) {
  659.       p_info->name_length = len;
  660.   } else {
  661.     p_info->name_length = rec->file_id_length;
  662.     memcpy (p_info->name, rec->file_id, rec->file_id_length);
  663.   }
  664.   if (p_dir->volume->protocol == PRO_ROCK &&
  665.       Is_A_Symbolic_Link (p_dir->volume, rec)) {
  666.     p_info->symlink_f = 1;
  667.     p_info->directory_f = 0;
  668.   } else if (p_dir->volume->protocol == PRO_ROCK &&
  669.              Has_System_Use_Field (p_dir->volume, rec, "CL")) {
  670.     p_info->symlink_f = 0;
  671.     p_info->directory_f = 1;
  672.   } else {
  673.     p_info->symlink_f = 0;
  674.     p_info->directory_f = rec->flags & 2;
  675.   }
  676.   p_info->file_length = rec->data_length_m;
  677.   p_info->date = Extract_Date (rec);
  678.   p_info->suppl_info = rec;
  679.  
  680.   return 1;
  681. }
  682.  
  683. /* Clone a "CDROM object info."
  684.  */
  685.  
  686. void *Iso_Clone_Obj_Info (void *p_info)
  687. {
  688.   t_iso_obj_info *info = (t_iso_obj_info *) p_info;
  689.   t_iso_obj_info *new;
  690.   
  691.   new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
  692.   if (!new)
  693.     return NULL;
  694.  
  695.   memcpy (new, info, sizeof (t_iso_obj_info));
  696.  
  697.   new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
  698.   if (!new->dir) {
  699.     FreeMem (new, sizeof (t_iso_obj_info));
  700.     return NULL;
  701.   }
  702.   memcpy (new->dir, info->dir, info->dir->length);
  703.  
  704.   return new;
  705. }
  706.  
  707. /* Find parent directory.
  708.  */
  709.  
  710. CDROM_OBJ *Iso_Find_Parent (CDROM_OBJ *p_object)
  711. {
  712.   directory_record *dir;
  713.   unsigned long dir_loc;
  714.   long pl;
  715.  
  716.   if (p_object->directory_f)
  717.     dir_loc = OBJ(p_object,dir)->extent_loc_m + OBJ(p_object,dir)->ext_attr_length;
  718.   else
  719.     dir_loc = OBJ(p_object,parent_loc);
  720.  
  721.   dir = Get_Directory_Record (p_object->volume, dir_loc, 0);
  722.   if (!dir)
  723.     return NULL;
  724.   
  725.   if (p_object->directory_f) {
  726.     dir = Get_Directory_Record (p_object->volume, dir_loc, dir->length);
  727.     if (!dir)
  728.       return NULL;
  729.     if (p_object->volume->protocol == PRO_ROCK &&
  730.         (pl = RR_Parent_Link (p_object->volume, dir)) >= 0)
  731.       return Iso_Create_Directory_Obj (p_object->volume, pl);
  732.   }
  733.  
  734.   return Iso_Create_Directory_Obj (p_object->volume, dir->extent_loc_m);
  735. }
  736.  
  737. /* Test if p_object is the root directory.
  738.  */
  739.  
  740. t_bool Iso_Is_Top_Level_Object (CDROM_OBJ *p_object)
  741. {
  742.   return p_object->directory_f &&
  743.          OBJ(p_object,dir)->extent_loc_m ==
  744.      VOL(p_object->volume,pvd).root.extent_loc_m;
  745. }
  746.  
  747. /* Test if two objects are equal.
  748.  */
  749.  
  750. t_bool Iso_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
  751. {
  752.   return (OBJ(p_obj1,dir)->extent_loc_m ==
  753.       OBJ(p_obj2,dir)->extent_loc_m);
  754. }
  755.  
  756. /*
  757.  * Convert p_num digits into an integer value:
  758.  */
  759.  
  760. int Digs_To_Int (char *p_digits, int p_num)
  761. {
  762.   int result = 0;
  763.   int i;
  764.   
  765.   for (i=0; i<p_num; i++)
  766.     result = result * 10 + p_digits[i] - '0';
  767.     
  768.   return result;
  769. }
  770.  
  771. /*
  772.  * Return volume creation date as number of seconds since 1-Jan-1978:
  773.  */
  774.  
  775. t_ulong Iso_Creation_Date (VOLUME *p_volume)
  776. {
  777.   struct ClockData ClockData;
  778.   char *dt = VOL(p_volume,pvd).vol_creation;
  779.  
  780.   ClockData.sec   = Digs_To_Int (dt+12, 2);
  781.   ClockData.min      = Digs_To_Int (dt+10, 2);
  782.   ClockData.hour  = Digs_To_Int (dt+8, 2);
  783.   ClockData.mday  = Digs_To_Int (dt+6, 2);
  784.   ClockData.wday  = 0; /* is ignored by CheckDate() and Date2Amiga() */
  785.   ClockData.month = Digs_To_Int (dt+4, 2);
  786.   ClockData.year  = Digs_To_Int (dt, 4);
  787.  
  788.   if (CheckDate (&ClockData))
  789.     return Date2Amiga (&ClockData);
  790.   else
  791.     return 0;
  792. }
  793.  
  794. t_ulong Iso_Volume_Size (VOLUME *p_volume)
  795. {
  796.   return VOL(p_volume,pvd).space_size_m;
  797. }
  798.  
  799. t_ulong Iso_Block_Size (VOLUME *p_volume)
  800. {
  801.   return VOL(p_volume,pvd).block_size_m;
  802. }
  803.  
  804. void Iso_Volume_ID (VOLUME *p_volume, char *p_buffer, int p_buf_length)
  805. {
  806.   char *iso_name = VOL(p_volume,pvd).volume_id;
  807.   int iso_len;
  808.   int len;
  809.  
  810.   for (iso_len = 30; iso_len; iso_len--) {
  811.     if (iso_name[iso_len-1] != ' ')
  812.       break;
  813.   }
  814.  
  815.   len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
  816.   if (len > 0)
  817.     memcpy (p_buffer, iso_name, len);
  818.   p_buffer[len] = 0;
  819. }
  820.  
  821. t_ulong Iso_Location (CDROM_OBJ *p_object)
  822. {
  823.   return OBJ(p_object,dir)->extent_loc_m;
  824. }
  825.  
  826. t_ulong Iso_File_Length (CDROM_OBJ *p_obj)
  827. {
  828.   return OBJ(p_obj,dir)->data_length_m;
  829. }
  830.  
  831. t_handler g_iso_handler = {
  832.   Iso_Close_Vol_Info,
  833.   Iso_Open_Top_Level_Directory,
  834.   Iso_Open_Obj_In_Directory,
  835.   Iso_Find_Parent,
  836.   Iso_Close_Obj,
  837.   Iso_Read_From_File,
  838.   Iso_CDROM_Info,
  839.   Iso_Examine_Next,
  840.   Iso_Clone_Obj_Info,
  841.   Iso_Is_Top_Level_Object,
  842.   Iso_Same_Objects,
  843.   Iso_Creation_Date,
  844.   Iso_Volume_Size,
  845.   Iso_Volume_ID,
  846.   Iso_Location,
  847.   Iso_File_Length,
  848.   Iso_Block_Size
  849. };
  850.  
  851. t_handler g_rr_handler = {
  852.   Iso_Close_Vol_Info,
  853.   Iso_Open_Top_Level_Directory,
  854.   Iso_Open_Obj_In_Directory,
  855.   Iso_Find_Parent,
  856.   Iso_Close_Obj,
  857.   Iso_Read_From_File,
  858.   Iso_CDROM_Info,
  859.   Iso_Examine_Next,
  860.   Iso_Clone_Obj_Info,
  861.   Iso_Is_Top_Level_Object,
  862.   Iso_Same_Objects,
  863.   Iso_Creation_Date,
  864.   Iso_Volume_Size,
  865.   Iso_Volume_ID,
  866.   Iso_Location,
  867.   Iso_File_Length,
  868.   Iso_Block_Size
  869. };
  870.  
  871.